home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
src.arc
/
ICMPCMD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-19
|
6KB
|
264 lines
/* ICMP-related user commands */
#include <stdio.h>
#include "global.h"
#include "icmp.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "timer.h"
#include "socket.h"
#include "proc.h"
#include "session.h"
#include "cmdparse.h"
#include "commands.h"
static int doicmpec __ARGS((int argc, char *argv[],void *p));
static int doicmpstat __ARGS((int argc, char *argv[],void *p));
static int doicmptr __ARGS((int argc, char *argv[],void *p));
static void pingtx __ARGS((int s,void *ping1,void *p));
static int pingem __ARGS((int s,int16 seq,int16 id,int16 len));
static struct cmds Icmpcmds[] = {
"echo", doicmpec, 0, 0, NULLCHAR,
"status", doicmpstat, 0, 0, NULLCHAR,
"trace", doicmptr, 0, 0, NULLCHAR,
NULLCHAR
};
int Icmp_trace;
static int Icmp_echo = 1;
int
doicmp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Icmpcmds,argc,argv,p);
}
static int
doicmpstat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register int i;
printf("ICMP: chksum err %u no space %u icmp %u bdcsts %u\n",
Icmp_errors.checksum,Icmp_errors.nospace,Icmp_errors.noloop,
Icmp_errors.bdcsts);
printf("type rcvd sent\n");
for(i=0;i<ICMP_TYPES;i++){
if(Icmp_stats.input[i] == 0 && Icmp_stats.output[i] == 0)
continue;
printf("%-6u%-6u%-6u",i,Icmp_stats.input[i],
Icmp_stats.output[i]);
printf(" %s",Icmptypes[i]);
printf("\n");
}
return 0;
}
static int
doicmptr(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Icmp_trace,"ICMP tracing",argc,argv);
}
static int
doicmpec(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
}
/* Send ICMP Echo Request packets */
int
doping(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct proc *pinger = NULLPROC; /* Transmit process */
struct sockaddr_in to,from;
struct icmp icmp;
struct mbuf *bp;
int32 timestamp,rtt,abserr;
int s,fromlen;
struct ping ping;
struct session *sp;
memset((char *)&ping,0,sizeof(ping));
/* Allocate a session descriptor */
if((sp = newsession(argv[1],PING)) == NULLSESSION){
printf("Too many sessions\n");
freeargs(argc,argv);
return 1;
}
sp->cb.ping = &ping;
ping.sp = sp;
ping.proc = Curproc;
if((sp->s = s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == -1){
printf("Can't create socket\n");
freesession(sp);
freeargs(argc,argv);
return 1;
}
Current = sp;
Mode = CONV_MODE;
to.sin_family = AF_INET;
if((to.sin_addr.s_addr = resolve(argv[1])) == 0){
printf("Host %s unknown\n",argv[1]);
close_s(s);
freesession(sp);
freeargs(argc,argv);
return 1;
}
connect(s,(char *)&to,sizeof(to));
if(argc > 2)
ping.len = atoi(argv[2]);
if(argc > 3)
ping.interval = atoi(argv[3]);
freeargs(argc,argv);
if(ping.interval != 0){
pinger = newproc("pingtx",300,pingtx,s,&ping,NULL);
} else {
/* One shot ping; let echo_proc hook handle response.
* An ID of MAXINT16 will not be confused with a legal socket
* number, which is used to identify repeated pings
*/
pingem(s,0,MAXINT16,ping.len);
close_s(s);
freesession(sp);
return 0;
}
/* Now collect the replies */
for(;;){
fromlen = sizeof(from);
if(recv_mbuf(s,&bp,0,0,(char *)&from,&fromlen) == -1)
break;
ntohicmp(&icmp,&bp);
if(icmp.type != ECHO_REPLY
|| from.sin_addr.s_addr != to.sin_addr.s_addr
|| icmp.args.echo.id != s){
/* Ignore other people's responses */
free_p(bp);
continue;
}
ping.responses++;
/* Get stamp */
if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
!= sizeof(timestamp)){
/* The timestamp is missing! */
free_p(bp); /* Probably not necessary */
continue;
}
free_p(bp);
/* Compute round trip time, update smoothed estimates */
rtt = (Clock - timestamp) * MSPTICK;
abserr = rtt > ping.srtt ? rtt - ping.srtt : ping.srtt - rtt;
if(ping.responses == 1){
/* First response, base entire SRTT on it */
ping.srtt = rtt;
} else {
ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
}
ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
}
if(Current == sp && Mode == CONV_MODE)
printf("\n");
if(pinger != NULLPROC)
killproc(pinger);
close_s(s);
freesession(sp);
return 0;
}
void
echo_proc(source,dest,icmp,bp)
int32 source;
int32 dest;
struct icmp *icmp;
struct mbuf *bp;
{
int32 timestamp,rtt;
if(Icmp_echo && icmp->args.echo.id == MAXINT16
&& pullup(&bp,(char *)×tamp,sizeof(timestamp))
== sizeof(timestamp)){
/* Compute round trip time */
rtt = (Clock - timestamp) * MSPTICK;
printf("%s: rtt %lu\n",inet_ntoa(source),rtt);
}
free_p(bp);
}
/* Ping transmit process. Runs until killed */
static void
pingtx(s,ping1,p)
int s; /* Socket to use */
void *ping1;
void *p;
{
struct ping *ping;
long sdur;
ping = (struct ping *)ping1;
sdur = ping->interval * (1000 / MSPTICK);
ping->sent = 0;
for(;;){
if(Current == ping->sp && Mode == CONV_MODE){
printf("pinging %s: sent %lu rcvd %lu avg rtt %lu mdev %lu \r",
ping->sp->name,ping->sent,ping->responses,ping->srtt,
ping->mdev);
}
pingem(s,(int16)ping->sent++,s,ping->len);
pause(sdur);
}
}
/* Send ICMP Echo Request packet */
static int
pingem(s,seq,id,len)
int s; /* Raw socket on which to send ping */
int16 seq; /* ICMP Echo Request sequence number */
int16 id; /* ICMP Echo Request ID */
int16 len; /* Length of optional data field */
{
struct mbuf *data = NULLBUF;
struct mbuf *bp;
struct icmp icmp;
if((data = alloc_mbuf(len+sizeof(Clock))) == NULLBUF)
return -1;
data->cnt = len+sizeof(Clock);
/* Set optional data field, if any, to all 55's */
if(len != 0)
memset(data->data+sizeof(Clock),0x55,len);
/* Insert timestamp and build ICMP header */
memcpy(data->data,(char *)&Clock,sizeof(Clock));
Icmp_stats.output[ECHO]++;
icmp.type = ECHO;
icmp.code = 0;
icmp.args.echo.seq = seq;
icmp.args.echo.id = id;
if((bp = htonicmp(&icmp,data)) == NULLBUF){
free_p(data);
return 0;
}
send_mbuf(s,bp,0,NULLCHAR,0);
return 0;
}